#pragma once
#include "../common/net.hpp"
#include "../common/message.hpp"

namespace zl
{
    namespace server
    {
        // 强类型枚举   不会隐式转换为整数
        enum class VType
        {
            BOOL = 0,
            INTEGRAL,
            NUMERIC,
            STRING,
            ARRAY,
            OBJECT
        };

        // 服务描述类
        class ServiceDescribe
        {
        public:
            using ptr = std::shared_ptr<ServiceDescribe>;
            using ServiceCallback = std::function<void(const Json::Value &, Json::Value &)>;
            using ParamsDescribe = std::pair<std::string, VType>;

            ServiceDescribe(const std::string &&method, ServiceCallback &&callback, VType returnType,
                            const std::vector<ParamsDescribe> &&params)
                : m_method(std::move(method)), m_callback(std::move(callback)), m_returnType(returnType), m_params(std::move(params))
            {
            }

            const std::string &method() const
            {
                return m_method;
            }

            // 收到1请求的参数校验
            bool paramCheck(const Json::Value &params)
            {
                // 对params 进行校验    参数是否存在  参数类型是否一致
                for (auto &desc : m_params)
                {
                    // 比对参数名称
                    if (params.isMember(desc.first) == false)
                    {
                        ELOG("参数字段完整性校验失败 %s 字段缺失", desc.first.c_str());
                        return false;
                    }
                    // 比对参数类型  一一对应
                    if (check(desc.second, params[desc.first]) == false)
                    {
                        ELOG("%s 参数字段类型不匹配", desc.first.c_str());
                        return false;
                    }
                }
                return true;
            }

            bool call(const Json::Value &params, Json::Value &result)
            {
                // 调用实际业务函数
                m_callback(params, result);

                if (return_result(result) == false)
                {
                    ELOG("返回结果类型不匹配");
                    return false;
                }

                return true;
            }

        private:
            bool return_result(const Json::Value &val)
            {
                return check(m_returnType, val);
            }

            bool check(VType vtype, const Json::Value &value)
            {
                switch (vtype)
                {
                case VType::BOOL:
                    return value.isBool();
                case VType::INTEGRAL:
                    return value.isIntegral();
                case VType::NUMERIC:
                    return value.isNumeric();
                case VType::STRING:
                    return value.isString();
                case VType::ARRAY:
                    return value.isArray();
                }

                return false;
            }

        private:
            std::string m_method;                 // 方法名称
            ServiceCallback m_callback;           // 实际业务回调函数
            std::vector<ParamsDescribe> m_params; // 参数字段格式描述 包含参数名称和参数类型
            VType m_returnType;                   // 返回值类型
        };

        class SDescribeFactory
        {
        public:
            void setMethodName(const std::string &method)
            {
                m_method = method;
            }

            void setReturnType(VType type)
            {
                m_returnType = type;
            }

            void setParamsDesc(const std::string &params, VType type)
            {
                m_params.push_back(ServiceDescribe::ParamsDescribe(params, type));
            }

            void setCallback(const ServiceDescribe::ServiceCallback &callback)
            {
                m_callback = callback;
            }

            ServiceDescribe::ptr build()
            {
                return std::make_shared<ServiceDescribe>(std::move(m_method), std::move(m_callback), m_returnType, std::move(m_params));
            }

        private:
            std::string m_method;                                  // 方法名称
            ServiceDescribe::ServiceCallback m_callback;           // 实际业务回调函数
            std::vector<ServiceDescribe::ParamsDescribe> m_params; // 参数字段格式描述 包含参数名称和参数类型
            VType m_returnType;                                    // 返回值类型
        };

        class ServiceManager
        {
        public:
            using ptr = std::shared_ptr<ServiceManager>;

            void insert(const ServiceDescribe::ptr &sd)
            {
                std::unique_lock<std::mutex> lock(m_mutex);
                m_services[sd->method()] = sd;
            }

            // 查
            ServiceDescribe::ptr select(const std::string &method)
            {
                std::unique_lock<std::mutex> lock(m_mutex);

                auto it = m_services.find(method);
                if (it != m_services.end())
                {
                    return it->second;
                }
                // 返回空指针
                return ServiceDescribe::ptr();
            }

            void remove(const std::string &method)
            {
                std::unique_lock<std::mutex> lock(m_mutex);
                m_services.erase(method);
            }

        private:
            std::mutex m_mutex;
            // 方法名称  服务描述
            std::unordered_map<std::string, ServiceDescribe::ptr> m_services;
        };

        class RpcRouter
        {
        public:
            using ptr = std::shared_ptr<RpcRouter>;
            RpcRouter()
                : m_serviceManager(std::make_shared<ServiceManager>())
            {
            }

            // 这是注册到Dispatcher模块针对rpc请求进行回调处理的业务函数
            void onRpcRequest(const BaseConnection::ptr &conn, RpcRequest::ptr &req)
            {
                // 1 查询client请求的方法描述，判断当前服务器是否能提供对应服务
                auto service = m_serviceManager->select(req->method());
                if (service.get() == nullptr)
                {
                    ELOG("%s 未找到该服务", req->method().c_str());
                    return response(conn, req, Json::Value(), RCode::RCODE_INTERNAL_ERROR);
                }

                // 2 进行参数校验，确定能否提供服务
                if (service->paramCheck(req->params()) == false)
                {
                    ELOG("%s 服务参数校验理失败", req->method().c_str());
                    return response(conn, req, Json::Value(), RCode::RCODE_INVALID_PARAMS);
                }

                // 3 调用业务回调接口进行业务处理
                Json::Value result;
                bool ret = service->call(req->params(), result);
                if (ret == false)
                {
                    ELOG("%s 结果参数校验理失败", req->method().c_str());
                    return response(conn, req, Json::Value(), RCode::RCODE_INTERNAL_ERROR);
                }

                // 4 处理完毕得到结果，组织响应，向客户端发送
                return response(conn, req, result, RCode::RECODE_OK);
            }

            void registerMethod(const ServiceDescribe::ptr &sd)
            {
                return m_serviceManager->insert(sd);
            }

        private:
            void response(const BaseConnection::ptr &conn, const RpcRequest::ptr &req,
                          const Json::Value &result, RCode code)
            {
                // 回应
                auto msg = MessageFactory::create<RpcResponse>();

                msg->setId(req->rid());
                msg->setMType(MType::RSP_RPC);
                msg->setRCode(code);
                msg->setresult(result);
                conn->send(msg);
            }

        private:
            ServiceManager::ptr m_serviceManager;
        };
    }
}
